<template>
  <div :class="['v-date-picker',extClass]" ref="datePickerObj">
    <div class="v-date-picker-header">
      <a
        href="javascript:;"
        v-if="showPrevNext"
        class="iconfont icon-arrow-right-line v-date-picker-header__prev"
        @click="prevOrNextDateChange(-1)"
      ></a>
      <span class="v-date-picker-header__label" @click="showDropList=!showDropList">
        <template v-if="dateValue.length>1">
          {{dateValueStr}}
          <i class="iconfont" v-if="showDroplistArrow">&#xe642;</i>
        </template>
      </span>
      <a
        href="javascript:;"
        v-if="showPrevNext"
        class="iconfont icon-arrow-right-line v-date-picker-header__next"
        @click="prevOrNextDateChange(1)"
      ></a>
    </div>
    <div
      v-show="showDropList"
      class="v-date-picker-droplist"
      ref="droplistBox"
      :style="{top:droplistTop+'px'}"
      @click="showDropList=false"
    >
      <div class="v-date-picker-droplist-header" @click.stop="showDropList=true">
        <div class="v-date-picker-droplist-yearhandler">
          <a
            href="javascript:;"
            class="iconfont icon-arrow-right-line v-date-picker-header__prev"
            @click="yearChangeHandler(-1)"
          ></a>
          {{selYear}}
          <a
            href="javascript:;"
            class="iconfont icon-arrow-right-line v-date-picker-header__next"
            @click="yearChangeHandler(1)"
          ></a>
        </div>
        <div class="v-date-picker-droplist-monthhandler" ref="monthList">
          <a
            href="javascript:;"
            class="month-item"
            v-for="(item,index) in monthList"
            :key="index"
            :class="[{active:+selMonth===index},{disabled:!checkMonthEnable(index)}]"
            @click="monthChangeHandler(index)"
          >{{item}}</a>
        </div>
      </div>
      <div class="v-date-picker-droplist-content" @click.stop="showDropList=true">
        <ul class="calendar-row calendar-row-header">
          <li class="week-value" v-if="showWeek"></li>
          <li v-for="(item,index) in weekList" :key="index">{{item}}</li>
        </ul>
        <ul class="calendar-row calendar-row-body" v-for="(item,index) in calendayArr" :key="index">
          <li class="week-value" v-if="showWeek">{{item.weekVal[1]}}周</li>
          <li
            class="day-cell"
            v-for="(item1,index1) in item.dayList"
            :key="index1"
            :class="[
          {disabled:(index===0 && item1.dateNum > 10) || (index>2 && item1.dateNum < 10) || !checkDateEnable(item1.date)},
          {active:item1.dateStr === dateValueStr}]"
            @click.stop="dateChangeHandler(item1)"
          >
            <span class="date-num">
              <template v-if="isToday(item1.date)">今</template>
              <template v-else>{{item1.dateNum}}</template>
            </span>
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>

<script>
/*
   功能模块  日期选择器
   创建人    zgf
   更新时间  2019/12/25
   页面参数  
   备注      
*/
import DateUtil from "./dateUtil.js";
export default {
  name: "VDatePicker",
  props: {
    value: {
      type: String,
      default: ""
    },
    maxDate: {
      type: String,
      default: ""
    },
    maxMsg: {
      type: String,
      default: ""
    },
    minDate: {
      type: String,
      default: ""
    },
    minMsg: {
      type: String,
      default: ""
    },
    showWeek: {
      type: Boolean,
      default: false
    },
    showPrevNext: {
      type: Boolean,
      default: true
    },
    showDroplistArrow: {
      type: Boolean,
      default: false
    },
    extClass: {
      type: String,
      default: ""
    }
  },
  data() {
    return {
      todayDate: new Date().getDate(),
      droplistTop: 0,
      showDropList: false,
      dateValue: [],
      selYear: 2019,
      selMonth: 10,
      monthList: [
        "1月",
        "2月",
        "3月",
        "4月",
        "5月",
        "6月",
        "7月",
        "8月",
        "9月",
        "10月",
        "11月",
        "12月"
      ],
      weekList: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
      calendayArr: []
    };
  },
  computed: {
    dateValueStr() {
      return DateUtil.formatDate(this.dateValue, "yyyy年MM月dd日");
    },
    scroller() {
      return DateUtil.getScrollEventTarget(this.$el);
    }
  },
  watch: {
    value: {
      deep: true,
      handler(newVal) {
        this.dateValue = newVal;
        this.calendarRender();
      }
    },
    dateValue: {
      deep: true,
      handler(newVal) {
        this.$emit("input", newVal);
      }
    },
    selMonth(newVal) {
      this.$refs.monthList.scrollLeft = 44 * newVal - 100;
    },
    showDropList(newVal) {
      if (newVal) {
        this.$emit("droplistOpen");
        this.$nextTick(() => {
          this.$refs.monthList.scrollLeft = 44 * this.selMonth - 100;
          this.updateOffsetTop();
        });
        this.scroller.addEventListener("scroll", this.onScroll);
      } else {
        this.$emit("droplistClose");
        this.scroller.removeEventListener("scroll", this.onScroll);
      }
    }
  },
  mounted() {
    this.setDefaultVal();
    this.yearAndMonthRender();
    document.addEventListener("click", e => {
      let ignNames = [
        "v-date-picker-header",
        "v-date-picker-header__label",
        "iconfont icon-arrow-right-line v-date-picker-header__next",
        "iconfont icon-arrow-right-line v-date-picker-header__prev"
      ];
      if (ignNames.indexOf(e.target.className) !== -1) {
        return false;
      }
      this.showDropList = false;
    });
  },
  methods: {
    //判断某日期是否是今天
    isToday(date) {
      let nowStr = DateUtil.formatDate(new Date(), "yyyyMMdd");
      let dateStr = DateUtil.formatDate(date, "yyyyMMdd");
      return nowStr === dateStr;
    },
    //计算top值
    updateOffsetTop() {
      let rect = this.$refs.datePickerObj.getBoundingClientRect();
      this.droplistTop = rect.y ? rect.y + rect.height : rect.top + rect.height;
    },
    //滚动时重新计算top值
    onScroll() {
      this.updateOffsetTop();
    },
    //字符串日期转换成数组形式
    dateStrToArr(dateStr) {
      if (dateStr === "") {
        dateStr = new Date();
      } else {
        dateStr = new Date(DateUtil.formatDate(dateStr, "yyyy/MM/dd"));
      }
      let y = dateStr.getFullYear();
      let m = dateStr.getMonth() + 1;
      let d = dateStr.getDate();
      return [y, m, d];
    },
    //输入值如果为空，默认当前周
    setDefaultVal() {
      this.dateValue = this.value;
      if (!this.value) {
        this.dateValue = DateUtil.formatDate(new Date(), "yyyy/MM/dd");
      }
      let dateValueArr = this.dateStrToArr(this.dateValue);
      this.selYear = dateValueArr[0];
      this.selMonth = dateValueArr[1] - 1;
      this.calendarRender();
    },
    //年月条条渲染
    yearAndMonthRender() {},
    //日历列表渲染
    calendarRender() {
      let dayOneDateObj = new Date(
        this.selYear + "/" + (+this.selMonth + 1) + "/1"
      );
      let firstDay = dayOneDateObj.getDay();
      firstDay = firstDay === 0 ? 7 : firstDay;
      let begin =
        dayOneDateObj.getTime() - (firstDay - 1) * 60 * 60 * 1000 * 24;
      let month2 = DateUtil.isLeapYear(this.selYear) ? 29 : 28; //2月平年28天，闰年29天
      let lastDayArr = [31, month2, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
      let lastDayObj = new Date(
        this.selYear +
          "/" +
          (+this.selMonth + 1) +
          "/" +
          lastDayArr[this.selMonth]
      );
      let lastDayWeek = lastDayObj.getDay();
      lastDayWeek = lastDayWeek === 0 ? 7 : lastDayWeek;
      let end = lastDayObj.getTime() + (7 - lastDayWeek) * 60 * 60 * 1000 * 24;
      let oneWeek = 7 * 24 * 60 * 60 * 1000;
      let oneDay = 1 * 24 * 60 * 60 * 1000;
      let calendayArr = [];
      for (var i = begin; i < end; i += oneWeek) {
        let l = i + 6 * 24 * 60 * 60 * 1000;
        let weekDaysArr = [];
        for (var j = i; j <= l; j += oneDay) {
          let dd = new Date(j);
          weekDaysArr.push({
            dateNum: dd.getDate(),
            date: dd,
            dateStr: DateUtil.formatDate(dd, "yyyy年MM月dd日")
          });
        }
        calendayArr.push({
          weekVal: DateUtil.getWeekByDate(new Date(i)),
          dayList: weekDaysArr
        });
      }
      this.calendayArr = calendayArr;
    },
    //前一天，后一天 切换
    prevOrNextDateChange(step) {
      let oneDay = 1 * 24 * 60 * 60 * 1000;
      let curSelectDateTime = new Date(
        DateUtil.formatDate(this.dateValue, "yyyy/MM/dd")
      ).getTime();
      let resultDate = null;
      if (step < 0) {
        //前一天
        resultDate = new Date(curSelectDateTime - oneDay);
      } else {
        //后一天
        resultDate = new Date(curSelectDateTime + oneDay);
      }
      if (!this.checkDateEnable(resultDate, true)) {
        return;
      }
      this.selMonth = resultDate.getMonth();
      this.selYear = resultDate.getFullYear();
      this.dateValue = DateUtil.formatDate(resultDate, "yyyy/MM/dd");
      this.$emit("change", this.dateValue);
      // this.showDropList = false
    },
    //年改变
    yearChangeHandler(step) {
      if (!this.checkYearEnable(this.selYear + step)) {
        return false;
      }
      this.selYear += step;
      this.calendarRender();
    },
    //月改变
    monthChangeHandler(index) {
      if (!this.checkMonthEnable(index, true)) {
        return false;
      }
      this.selMonth = index;
      this.calendarRender();
    },
    //日期改变
    dateChangeHandler(item) {
      if (!this.checkDateEnable(item.date, true)) {
        return;
      }
      this.showDropList = false;
      let arr = this.dateStrToArr(item.date);
      this.selYear = arr[0];
      this.selMonth = arr[1] - 1;
      this.dateValue = DateUtil.formatDate(item.date, "yyyy/MM/dd");
      this.$emit("change", this.dateValue);
    },
    //检查年是否超出范围
    checkYearEnable(year) {
      if (this.maxDate) {
        let maxYear = new Date(
          DateUtil.formatDate(this.maxDate, "yyyy/MM/dd")
        ).getFullYear();
        if (year > maxYear) {
          if (this.maxMsg) this.$toast(this.maxMsg);
          return false;
        }
      }
      if (this.minDate) {
        let minYear = new Date(
          DateUtil.formatDate(this.minDate, "yyyy/MM/dd")
        ).getFullYear();
        if (year < minYear) {
          if (this.minMsg) this.$toast(this.minMsg);
          return false;
        }
      }
      return true;
    },
    //检查日期是否超出范围
    checkDateEnable(dateVal, showMsg) {
      let curStr = DateUtil.formatDate(dateVal, "yyyyMMdd");
      if (this.maxDate) {
        let maxStr = DateUtil.formatDate(this.maxDate, "yyyyMMdd");
        if (+curStr > +maxStr) {
          if (this.maxMsg && showMsg) this.$toast(this.maxMsg);
          return false;
        }
      }
      if (this.minDate) {
        let minStr = DateUtil.formatDate(this.minDate, "yyyyMMdd");
        if (+curStr < +minStr) {
          if (this.minMsg && showMsg) this.$toast(this.minMsg);
          return false;
        }
      }
      return true;
    },
    //检查月是否超出范围
    checkMonthEnable(index, showMsg) {
      if (this.maxDate) {
        let maxDate = new Date(DateUtil.formatDate(this.maxDate, "yyyy/MM/dd"));
        let maxDateTime = maxDate.getTime();
        let curMonthTime = new Date(
          this.selYear + "/" + (index + 1) + "/01 00:00:00"
        ).getTime();
        if (curMonthTime > maxDateTime) {
          if (this.maxMsg && showMsg) this.$toast(this.maxMsg);
          return false;
        }
      }
      if (this.minDate) {
        let minDate = new Date(DateUtil.formatDate(this.minDate, "yyyy/MM/dd"));
        let minDateTime = minDate.getTime();
        let curSelMonthLastDay = DateUtil.getStartAndEndDateByMonth([
          this.selYear,
          index + 1
        ]).endDate;
        let curMonthTime = new Date(curSelMonthLastDay + " 00:00:00").getTime();
        if (curMonthTime < minDateTime) {
          if (this.minMsg && showMsg) this.$toast(this.minMsg);
          return false;
        }
      }
      return true;
    }
  }
};
</script>

<style scoped lang="less">
//引入mixin和var
@import "../../../css/mixin.less";
.v-date-picker {
  height: 44px;
  padding-left: 15px;
  padding-right: 15px;
  justify-content: center;
  align-items: center;
  display: flex;
  background-color: #fff;
  &-droplist {
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.1);
    position: fixed;
    z-index: 2;
    &-header {
      background-color: #fff;
      position: relative;
      height: 50px;
      display: flex;
      font-size: 13px;
      background-color: #f7f7f7;
      .hairline(bottom, #eee);
    }
    &-yearhandler {
      display: flex;
      justify-content: center;
      align-items: center;
      margin-right: 10px;
    }
    &-monthhandler {
      flex: 1;
      white-space: nowrap;
      overflow-x: auto;
      overflow-y: hidden;
      -webkit-overflow-scrolling: touch;
      .month-item {
        width: 48px;
        display: inline-block;
        height: 48px;
        justify-content: center;
        line-height: 48px;
        color: #333;
        text-align: center;
        &.disabled {
          opacity: 0.4;
          &:active {
            color: #333;
          }
        }
        &:active {
          color: @color-primary;
        }
        &.active {
          color: @color-primary;
          font-weight: bold;
        }
      }
    }
    &-content {
      background-color: #fff;
      padding-bottom: 15px;
    }
  }
  &-header {
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    &__label {
      font-size: 14px;
      display: flex;
      height: 100%;
      justify-content: center;
      align-items: center;
      i {
        font-size: 12px;
        margin-left: 4px;
      }
      &:active {
        opacity: 0.8;
      }
    }
    &__prev {
      transform: rotate(180deg);
    }
    &__prev,
    &__next {
      display: flex;
      width: 44px;
      height: 44px;
      justify-content: center;
      align-items: center;
      color: #999;
      font-size:16px;
      &.disabled {
        opacity: 0.3;
      }
      &:active {
        background-color: #fafafa;
      }
    }
  }
}
.calendar-row {
  display: flex;
  &-header {
    border-bottom: solid 1px #f3f3f3;
    &:active {
      opacity: 1;
    }
    li {
      color: #aaa;
      font-weight: bold;
    }
  }
  li {
    flex: 1;
    display: flex;
    font-size: 12px;
    justify-content: center;
    align-items: center;
    height: 48px;
    &.day-cell {
      font-size: 14px;
    }
    &:active,
    &.active {
      .date-num {
        width: 40px;
        height: 40px;
        background-color: @color-primary;
        color: #fff;
        border-radius: 200px;
        display: flex;
        justify-content: center;
        align-items: center;
        font-weight: bold;
      }
    }
    &.week-value {
      color: #999;
      border-right: solid 1px #f3f3f3;
    }
    &.disabled {
      opacity: 0.2;
    }
  }
}
.date-picker-block {
  width: 100%;
  box-sizing: border-box;
  .v-date-picker-header__label {
    width: 100%;
  }
}
</style>
